package cursorx

import (
	"encoding/base64"
	"errors"
	"fmt"
	"strconv"
	"strings"

	"github.com/google/uuid"
)

type Input struct {
	After          *string
	Before         *string
	CursorSplitter string
	DefaultLimit   int
	First          *int
	Last           *int
}

type Output struct {
	After                 int64
	DefaultOrderAscending bool
	Limit                 int
}

func Encode(modelName string, uniqueKey string, splitter string) string {
	key := fmt.Sprintf("%s%s%s", modelName, splitter, uniqueKey)
	return base64.RawURLEncoding.EncodeToString([]byte(key))
}

func Decode(cursor string, splitter string) (string, string, error) {
	bytes, err := base64.RawURLEncoding.DecodeString(cursor)
	if err != nil {
		return "", "", err
	}

	arrStr := strings.Split(string(bytes), splitter)
	if len(arrStr) != 2 {
		err = errors.New("cursor is invalid")
		return "", "", err
	}

	return arrStr[0], arrStr[1], nil
}

func Parse(in *Input) (*Output, error) {
	if in == nil {
		return nil, errors.New("cursor input is missing")
	}

	var after int64
	var limit int
	var isAsc bool = true

	if in.DefaultLimit > 0 {
		limit = in.DefaultLimit
	}
	if in.After != nil && *in.After != "" {
		_, key, err := Decode(*in.After, in.CursorSplitter)
		if err != nil {
			return nil, err
		}

		if i, err := strconv.ParseInt(key, 10, 64); err == nil {
			after = i
		}
		if in.First != nil && *in.First > 0 {
			limit = int(*in.First)
		}
	} else if in.Before != nil && *in.Before != "" {
		_, key, err := Decode(*in.Before, in.CursorSplitter)
		if err != nil {
			return nil, err
		}

		isAsc = false
		if i, err := strconv.ParseInt(key, 10, 64); err == nil {
			after = i
		}
		if in.Last != nil && *in.Last > 0 {
			limit = int(*in.Last)
		}
	}

	return &Output{
		After:                 after,
		DefaultOrderAscending: isAsc,
		Limit:                 limit,
	}, nil
}

func CreateUniqueID() string {
	return strings.Replace(uuid.New().String(), "-", "", -1)
}
